package avicit.bdp.dds.api.service;

import avicit.bdp.common.dto.upload.ResumeUploadDto;
import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.common.utils.ConfigUtils;
import avicit.bdp.common.utils.enums.UploadStatus;
import avicit.bdp.common.utils.uploads.CatalogBean;
import avicit.bdp.common.utils.uploads.FileAdapterUtils;
import avicit.bdp.common.utils.uploads.FileBean;
import avicit.bdp.common.utils.uploads.IFileAdapter;
import avicit.bdp.core.constant.Constants;
import avicit.bdp.dds.api.dto.CatalogDto;
import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2020-09-24 14:55
 * @类说明：文件管理实现类
 * @修改记录：
 */
@Service
@Transactional
public class FileService {

    private static final Logger logger = LoggerFactory.getLogger(FileService.class);

    public List<FileBean> getFileList(String fileName, String catalogPath, Long startTime, Long endTime,
                                      String projectId) throws Exception {
        List<String> wordSecretList = ThreadContextHelper.getWordSecretList();
        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);
        return fileAdapter.getFileList(fileName, catalogPath, startTime, endTime, wordSecretList);
    }

    public Boolean deleteFileByPaths(String filePaths) throws Exception {
        if (StringUtils.isEmpty(filePaths)) {
            logger.error("删除文件失败,filePaths={}", filePaths);
            throw new BusinessException("没有传入待删除的文件路径");
        }

        // 递归方式删除文件或目录
        String[] filePathsArr = filePaths.split(Constants.COMMA);

        String projectId = FileAdapterUtils.getProjectIdFromPath(filePathsArr[0]);
        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);

        for (String filePath : filePathsArr) {

            if (fileAdapter.exists(filePath)) {
                if (!fileAdapter.delete(filePath, false)) {
                    logger.error("递归方式删除文件%s失败：{}", filePath);
                    throw new BusinessException(String.format("递归方式删除文件%s失败", filePath));
                }
            }

        }
        return true;
    }

    public CatalogBean getCatalogTree(String catalogPath, String projectId) throws Exception {
        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);

        return fileAdapter.getFileTreeList(catalogPath, "dir", "");
    }

    public List<CatalogBean> getCatalogTreeByCatalogPath(String catalogPath, String projectId) throws Exception {
        CatalogBean catalogBean = getCatalogTree(catalogPath, projectId);
        List<CatalogBean> childrenList = catalogBean.getChildren();
        return childrenList;
    }

    public Boolean deleteCatalogByPath(String catalogPath) {
        if (StringUtils.isEmpty(catalogPath)) {
            throw new BusinessException("没有传入待删除的目录路径");
        }

        try {
            String projectId = FileAdapterUtils.getProjectIdFromPath(catalogPath);
            IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);

            fileAdapter.delete(catalogPath, false);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BusinessException("删除文件失败，提示：非空目录不能删除！");
        }

        return true;
    }

    public Boolean saveCatalog(CatalogDto catalogDto) throws Exception {
        String parentCatalogPath = catalogDto.getParentCatalogPath();
        String projectId = FileAdapterUtils.getProjectIdFromPath(parentCatalogPath);
        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);

        String catalogName = catalogDto.getCatalogName();
        if (StringUtils.isEmpty(catalogName)) {
            throw new BusinessException("创建的文件目录名称不能为空！");
        }

        logger.info("创建目录名称为：{}", parentCatalogPath + Constants.SINGLE_SLASH + catalogName);
        return fileAdapter.mkdir(parentCatalogPath + Constants.SINGLE_SLASH + catalogName);
    }


    public Boolean rename(String srcPath, String dstPath) throws Exception {
        if (StringUtils.isEmpty(srcPath) || StringUtils.isEmpty(dstPath)) {
            throw new BusinessException("源文件名称或目的文件名称全路径不能为空");
        }

        String projectId = FileAdapterUtils.getProjectIdFromPath(dstPath);
        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);


        logger.info("源文件名称全路径为：{}，目的文件全路径为：{}", srcPath, dstPath);
        return fileAdapter.rename(srcPath, dstPath);
    }


    /**
     * 获取百分比
     */
    public String getPercent(Long num, Long totalPeople) {
        String percent;
        double p3;
        if (totalPeople == 0) {
            p3 = 0.0;
        } else {
            p3 = num * 1.0 / totalPeople;
        }
        NumberFormat nf = NumberFormat.getPercentInstance();
        // 控制保留小数点后几位，2：表示保留2位小数点
        nf.setMinimumFractionDigits(2);
        percent = nf.format(p3);
        return percent;
    }


    public CatalogBean getFileTreeList(String projectId, String catalogPath, String type, String defaultFilePath) throws Exception {
        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);

        return fileAdapter.getFileTreeList(catalogPath, type, defaultFilePath);
    }


    /**
     * 文件上传
     *
     * @param resumeUploadDto
     * @return void
     */
    public void upload(ResumeUploadDto resumeUploadDto) {
        String filePath = resumeUploadDto.getHdfsPath();
        String projectId = FileAdapterUtils.getProjectIdFromPath(filePath);

        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);

        Long startTime = System.currentTimeMillis();
        logger.debug("开始上传：{}, 参数：{}", startTime, resumeUploadDto);
        try {
            // 上传文件
            fileAdapter.upload(resumeUploadDto);

            Long endTime = System.currentTimeMillis();
            logger.info("上传文件{}, 分片{}/{}成功, 耗时：{}", resumeUploadDto.getFileName(), resumeUploadDto.getChunk(),
                    resumeUploadDto.getChunks(), endTime - startTime);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 获取文件上传是否成功[成功，暂停，失败的话响应，否则等待]
     *
     * @param resumeUploadDto resumeUploadDto
     * @throws Exception e
     */
    public Map<String, String> mergeChunks(ResumeUploadDto resumeUploadDto) throws Exception {

        String hdfsPath = resumeUploadDto.getHdfsPath();
        String fileName = resumeUploadDto.getFileName();
        Long fileSize = resumeUploadDto.getFileSize();
        CheckParaUtils.checkStringValidity(hdfsPath, logger, "hdfsPath不能为空");
        CheckParaUtils.checkStringValidity(fileName, logger, "fileName不能为空");
        CheckParaUtils.checkLongValidity(fileSize, logger, "fileSize不能为空");

        logger.info("开始合并分片信息...");
        Map<String, String> map = new HashMap<>(16);

        String filePath = resumeUploadDto.getHdfsPath();
        String projectId = FileAdapterUtils.getProjectIdFromPath(filePath);

        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);
        boolean isSuccess = false;
        try {
            isSuccess = fileAdapter.mergeFileToSave(resumeUploadDto);
        } catch (Exception e) {
            //合并任务失败
            logger.error(e.getMessage(), e);
            isSuccess = false;
        }

        if (!isSuccess) {
            map.put("status", UploadStatus.FAILED.getCode() + "");
            map.put("desc", UploadStatus.FAILED.getDesc());
        } else {
            map.put("status", UploadStatus.SUCCESS.getCode() + "");
            map.put("desc", UploadStatus.SUCCESS.getDesc());
        }
        logger.info("合并文件成功..." + filePath + "/" + fileName);
        return map;
    }

    /**
     * 获取已经上传的分片信息
     *
     * @param fileMd5  fileMd5
     * @param hdfsPath hdfsPath
     */
    public Map<String, List<Integer>> getUploadedChunkInfos(String fileMd5, String hdfsPath, String fileName) {
        return FileAdapterUtils.getUploadedChunkInfos(fileMd5, hdfsPath, fileName);
    }

    public Boolean deleteFileUpload(String fileMd5, String hdfsPath, String fileName) throws IOException {
        // 参数校验
        CheckParaUtils.checkStringValidity(fileMd5, logger, "fileMd5不能为空");
        CheckParaUtils.checkStringValidity(hdfsPath, logger, "hdfsPath不能为空");
        CheckParaUtils.checkStringValidity(fileName, logger, "fileName不能为空");

        String projectId = FileAdapterUtils.getProjectIdFromPath(hdfsPath);

        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);
        fileAdapter.deleteFileUpload(fileMd5, hdfsPath, fileName);

        return true;
    }


    /**
     * 下载文件
     *
     * @param filePath filePath
     * @param request  request
     * @param response response
     */
    public void downloadFile(String filePath, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String projectId = FileAdapterUtils.getProjectIdFromPath(filePath);

        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);
        fileAdapter.downloadFile(filePath, request, response);
    }

    /**
     * 获取分片大小
     */
    public Long getChunkSize() {
        // 分片大小默认40M
        return 41943040L;
    }

    /**
     * 获取上传类型
     */
    public Boolean getUploadType() {
        // 文件上传默认为append方式
        boolean append = ConfigUtils.getInstance().getBoolean(Constants.HDFS_SUPPORT_APPEND, false);

        return append;
    }


    /**
     * 判断文件是否存在
     *
     * @param map map
     */
    public Map<String, Boolean> checkFileExist(Map<String, Object> map) throws IOException {
        // 参数校验
        List<String> fileLists = (List<String>) map.get("fileList");
        CheckParaUtils.checkObjectValidity(fileLists, logger, "fileList不能为空");
        String catalogPath = (String) map.get("catalogPath");
        CheckParaUtils.checkStringValidity(catalogPath, logger, "目录不能为空");

        String projectId = FileAdapterUtils.getProjectIdFromPath(catalogPath);

        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(projectId);
        // 遍历文件名列表判断文件是否存在
        Map<String, Boolean> resultMap = new HashMap<String, Boolean>(16);
        for (String fileName : fileLists) {
            boolean exists = fileAdapter.exists(catalogPath + File.separator + fileName);
            resultMap.put(fileName, exists);
        }
        return resultMap;
    }
}
